#pragma once

#include <iostream>
#include <pthread.h>
#include <string>
#include <cstdint>
#include <functional>

namespace ThreadModule
{
    static uint32_t number = 1;
    class Thread
    {
        using task_t = std::function<void()>;
    private:
        void EnableRunning()
        {
            _isrunning = true;
        }

        void EnableDetach()
        {
            _is_detach = true;
        }

        static void *Routine(void *args)
        {
            Thread *self = static_cast<Thread *>(args);
            self->EnableRunning();
            if(self->_is_detach)
                self->Detach();
            self->_task();
        }
    public:
        Thread()
            : _tid(0), _isrunning(false), _is_detach(false), _ret(nullptr)
        {
            _name = "Thread-" + std::to_string(number++);
        }

        bool Start()
        {
            if(_isrunning)
                return;
            int n = pthread_create(&_tid, nullptr, Routine, this);
            (void)n;
        }

        bool Join()
        {
            if(_is_detach)
                return;
            int n = pthread_join(_tid, &_ret);
        }

        bool Cancel()
        {
            if(!_isrunning)
                return;
            int n = pthread_cancel(_tid);
            (void)n;
            _isrunning = false;
        }

        void Detach()
        {
            if(!_is_detach)
                return;
            if(!_isrunning)
                return;
            EnableDetach();
            int n = pthread_detach(_tid);
            (void)n;
        }

        ~Thread()
        {
        }

    private:
        pthread_t _tid;
        std::string _name;

        bool _isrunning;
        bool _is_detach;

        task_t _task;
        void *_ret;
    };
}